﻿/* ================================================================================
<copyright file="LogEventItemTest.cs" company="The Framework Factory, LLC" lastWriteTime="12/05/2012 23:23:47 PM">
  Copyright (c) 2012 The Framework Factory, LLC.  All rights reserved.
</copyright>
=================================================================================== */
using System;
using System.Data;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.XPath;

using NUnit.Framework;

using log4net.Core;

namespace FWF.Logging.Test
{
    /// <summary>
    /// 
    /// </summary>
    [TestFixture]
    public class LogEventItemTest
    {

        private static LogEventItem _logEventItem;

        private readonly DataTable _dataTable = new DataTable( "Messages" );

        private static readonly DateTime _testTimestamp = DateTime.Now;
        private const string TestMessage = "This is a test message";
        private readonly Level _testLevel = Level.Debug;
        private const long TestId = 1234;
        private const string TestExceptionType = "BadException";
        private const string TestExceptionMessage = "This is a test exception message";
        private const string TestLoggerName = "TestLogger";

        /// <summary>
        /// Tests the fixture setup.
        /// </summary>
        [TestFixtureSetUp]
        public void TestFixtureSetup()
        {
            //
            LogEventItem.PopulateDataTable( _dataTable );
        }

        /// <summary>
        /// Setups this instance.
        /// </summary>
        [SetUp]
        public void Setup()
        {
            _logEventItem = new LogEventItem();
            _logEventItem.Id = TestId;
            _logEventItem.TimeStamp = _testTimestamp;
            _logEventItem.LoggerName = TestLoggerName;
            _logEventItem.Message = TestMessage;
            _logEventItem.LevelName = _testLevel.Name;
            _logEventItem.LevelValue = _testLevel.Value;
            _logEventItem.ExceptionMessage = TestExceptionMessage;
            _logEventItem.ExceptionType = TestExceptionType;

            _logEventItem.ClassName = "className";
            _logEventItem.FileName = "fileName";
            _logEventItem.Identity = "identity";
            _logEventItem.LineNumber = 1;
            _logEventItem.MachineName = "machineName";
            _logEventItem.MethodName = "methodName";
            _logEventItem.ThreadName = "threadName";
            _logEventItem.UserName = "userName";
            _logEventItem.AppDomainName = "domain";

            //
            _logEventItem.InstanceName = "instanceName";
            _logEventItem.SessionId = 1;
            _logEventItem.SessionContext = "sessionContext";
            _logEventItem.SessionName = "sessionName";
            _logEventItem.ExceptionType = "exceptionType";

            
        }

        /// <summary>
        /// To the XML.
        /// </summary>
        [Test]
        public void ToXml()
        {
            var stringBuilder = new StringBuilder();

            using ( var stringWriter = new StringWriter( stringBuilder ) )
            {
                using ( XmlWriter xmlWriter = new XmlTextWriter( stringWriter ) )
                {
                    _logEventItem.ToXml( xmlWriter );
                }
            }

            Debug.WriteLine( stringBuilder.ToString() );

            Assert.IsNotEmpty( stringBuilder.ToString() );
        }

        /// <summary>
        /// Froms the XML.
        /// </summary>
        [Test]
        public void FromXml()
        {
            // Set the Id property to some arbitrary value to detect that 
            // xml serialization has completed successfully
            const int arbitraryValue = 1234;
            _logEventItem.Id = arbitraryValue;

            var stringBuilder = new StringBuilder();

            using ( var stringWriter = new StringWriter( stringBuilder ) )
            {
                using ( XmlWriter xmlWriter = new XmlTextWriter( stringWriter ) )
                {
                    _logEventItem.ToXml( xmlWriter );
                }
            }

            Debug.WriteLine( stringBuilder.ToString() );

            var xmlDoc = new XmlDocument();
            xmlDoc.LoadXml( stringBuilder.ToString() );

            XPathNavigator xPathNavigator = xmlDoc.CreateNavigator();
            xPathNavigator.MoveToRoot();
            xPathNavigator.MoveToFirstChild();

            var logEventItem = new LogEventItem();
            logEventItem.FromXml( xPathNavigator );

            Assert.AreEqual( arbitraryValue, logEventItem.Id );
        }

        /// <summary>
        /// To the and from logging event data.
        /// </summary>
        [Test]
        public void ToAndFromLoggingEventData()
        {
            LoggingEventData loggingEventData = _logEventItem.ToLoggingEventData();

            Assert.IsNotEmpty( loggingEventData.Message );
            Assert.IsNotEmpty( loggingEventData.Domain );
            Assert.IsNotEmpty( loggingEventData.ExceptionString );
            Assert.IsNotEmpty( loggingEventData.Identity );
            Assert.IsNotEmpty( loggingEventData.LoggerName );

            Assert.IsNotEmpty( loggingEventData.ThreadName );
            Assert.IsNotEmpty( loggingEventData.UserName );

            Assert.Greater( loggingEventData.TimeStamp.Ticks, 0 );

            Assert.IsNotNull( loggingEventData.Level );
            Assert.IsNotEmpty( loggingEventData.Level.Name );
            Assert.Greater( loggingEventData.Level.Value, 0 );

            Assert.IsNotNull( loggingEventData.LocationInfo );
            Assert.IsNotEmpty( loggingEventData.LocationInfo.ClassName );
            Assert.IsNotEmpty( loggingEventData.LocationInfo.FileName );
            Assert.IsNotEmpty( loggingEventData.LocationInfo.FullInfo );
            Assert.IsNotEmpty( loggingEventData.LocationInfo.LineNumber );
            Assert.IsNotEmpty( loggingEventData.LocationInfo.MethodName );

            Assert.IsNotNull( loggingEventData.Properties );

            LogEventItem logEventItem = LogEventItem.FromLoggingEventData( loggingEventData );

            CheckAllLogItemEventProperties( logEventItem );
        }

        /// <summary>
        /// To the and from data row.
        /// </summary>
        [Test]
        public void ToAndFromDataRow()
        {
            DataRow dataRow = _logEventItem.ToDataRow( _dataTable );

            LogEventItem logEventItem = LogEventItem.FromDataRow( dataRow );

            CheckAllLogItemEventProperties( logEventItem );
        }

        /// <summary>
        /// Checks all log item event properties.
        /// </summary>
        /// <param name="logEventItem">The log event item.</param>
        private static void CheckAllLogItemEventProperties( LogEventItem logEventItem )
        {
            Assert.IsNotEmpty( logEventItem.Message );
            Assert.IsNotEmpty( logEventItem.ClassName );
            Assert.IsNotEmpty( logEventItem.ExceptionMessage );
            Assert.IsNotEmpty( logEventItem.FileName );
            Assert.IsNotEmpty( logEventItem.Identity );
            Assert.IsNotEmpty( logEventItem.LevelName );
            Assert.IsNotEmpty( logEventItem.LoggerName );
            Assert.IsNotEmpty( logEventItem.MethodName );
            Assert.IsNotEmpty( logEventItem.ThreadName );
            Assert.IsNotEmpty( logEventItem.UserName );

            Assert.Greater( logEventItem.TimeStamp.Ticks, DateTime.MinValue.Ticks );
            Assert.Greater( logEventItem.LevelValue, -1 );
            Assert.Greater( logEventItem.LineNumber, -1 );

            Assert.IsNotNull( logEventItem.Properties );

            // Known issues where these properties are not preserved
            Assert.Greater( logEventItem.Id, -1 );
            Assert.IsNotEmpty( logEventItem.MachineName );
            Assert.IsNotEmpty( logEventItem.ExceptionType );
            Assert.IsNotEmpty( logEventItem.InstanceName );
            Assert.IsNotEmpty( logEventItem.SessionContext );
            Assert.IsNotEmpty( logEventItem.SessionName );
            Assert.Greater( logEventItem.SessionId, -1 );

        }

    }
}
